"""矩阵性质判定模块
包含正定性、对称性、相似性等判定功能
"""
import numpy as np
from scipy.linalg import eigvals, norm
from typing import Tuple

class MatrixProperties:
    @staticmethod
    def is_positive_definite(matrix: np.ndarray, tol: float = 1e-10) -> bool:
        """
        判断是否为正定矩阵
        :param matrix: 输入方阵
        :param tol: 容差
        :return: 是否为正定矩阵
        """
        try:
            if not MatrixProperties.is_symmetric(matrix, tol):
                return False
            
            eigenvals = np.linalg.eigvals(matrix)
            return bool(np.all(eigenvals > tol))
        except Exception as e:
            print(f"Error in is_positive_definite: {e}")
            return False
    
    @staticmethod
    def is_positive_semidefinite(matrix: np.ndarray, tol: float = 1e-10) -> bool:
        """
        判断是否为半正定矩阵
        :param matrix: 输入方阵
        :param tol: 容差
        :return: 是否为半正定矩阵
        """
        try:
            if not MatrixProperties.is_symmetric(matrix, tol):
                return False
            
            eigenvals = np.linalg.eigvals(matrix)
            return bool(np.all(eigenvals >= -tol))
        except Exception as e:
            print(f"Error in is_positive_semidefinite: {e}")
            return False
    
    @staticmethod
    def is_symmetric(matrix: np.ndarray, tol: float = 1e-10) -> bool:
        """
        判断是否为对称矩阵
        :param matrix: 输入方阵
        :param tol: 容差
        :return: 是否为对称矩阵
        """
        return bool(np.allclose(matrix, matrix.T, atol=tol))
    
    @staticmethod
    def is_antisymmetric(matrix: np.ndarray, tol: float = 1e-10) -> bool:
        """
        判断是否为反对称矩阵
        :param matrix: 输入方阵
        :param tol: 容差
        :return: 是否为反对称矩阵
        """
        return bool(np.allclose(matrix, -matrix.T, atol=tol))
    
    @staticmethod
    def is_hermitian(matrix: np.ndarray, tol: float = 1e-10) -> bool:
        """
        判断是否为厄米矩阵
        :param matrix: 输入方阵
        :param tol: 容差
        :return: 是否为厄米矩阵
        """
        return bool(np.allclose(matrix, matrix.conj().T, atol=tol))
    
    @staticmethod
    def matrix_rank(matrix: np.ndarray, tol: float = 1e-10) -> int:
        """
        计算矩阵秩
        :param matrix: 输入矩阵
        :param tol: 容差
        :return: 矩阵秩
        """
        return np.linalg.matrix_rank(matrix, tol=tol)
    
    @staticmethod
    def condition_number(matrix: np.ndarray, p=2) -> float:
        """
        计算条件数
        :param matrix: 输入矩阵
        :param p: 范数类型，默认为2范数
        :return: 条件数
        """
        try:
            # 确保p参数是有效的
            if p not in [1, 2, -1, -2, np.inf, -np.inf, 'fro']:
                p = 2  # 默认使用2范数
            return float(np.linalg.cond(matrix, p=p))
        except Exception as e:
            print(f"Error in condition_number: {e}")
            return float('inf')
    
    @staticmethod
    def spectral_radius(matrix: np.ndarray) -> float:
        """
        计算谱半径
        :param matrix: 输入方阵
        :return: 谱半径
        """
        try:
            # 确保输入是方阵
            if matrix.shape[0] != matrix.shape[1]:
                raise ValueError("Matrix must be square")
            
            # 检查矩阵是否包含无效值
            if not np.isfinite(matrix).all():
                raise ValueError("Matrix contains non-finite values")
            
            eigenvals = np.linalg.eigvals(matrix)
            return float(np.max(np.abs(eigenvals)))
        except Exception as e:
            print(f"Error in spectral_radius: {e}")
            return 0.0
    
    @staticmethod
    def are_similar(matrix1: np.ndarray, matrix2: np.ndarray, tol: float = 1e-10) -> bool:
        """
        判断两个矩阵是否相似
        :param matrix1: 第一个矩阵
        :param matrix2: 第二个矩阵
        :param tol: 容差
        :return: 是否相似
        """
        # 相似矩阵有相同的特征值
        eig1 = np.sort(np.linalg.eigvals(matrix1))
        eig2 = np.sort(np.linalg.eigvals(matrix2))
        return bool(np.allclose(eig1, eig2, atol=tol))
    
    @staticmethod
    def frobenius_norm(matrix: np.ndarray) -> float:
        """
        计算Frobenius范数
        :param matrix: 输入矩阵
        :return: Frobenius范数
        """
        return np.linalg.norm(matrix, 'fro')
    
    @staticmethod
    def nuclear_norm(matrix: np.ndarray) -> float:
        """
        计算核范数（奇异值之和）
        :param matrix: 输入矩阵
        :return: 核范数
        """
        singular_values = np.linalg.svd(matrix, compute_uv=False)
        return np.sum(singular_values)